#ifndef __H_DBTABLE__
#define __H_DBTABLE__
#include "util.hpp"
#include <mutex>
#include <cassert>

//用户表类
class user_table
{
    bool select_common(Json::Value& user,MYSQL_RES* res)
    {
        //只可能有一行
        int num_row = mysql_num_rows(res);
        if(num_row != 1)
        {
            ELOG("user information isn't unique");
            return false;
        }
        int num_col = mysql_num_fields(res);
        MYSQL_ROW row = mysql_fetch_row(res);
        user["username"] = row[2];
        user["id"] = std::stoull(row[0]);
        user["score"] = std::stoi(row[1]);
        user["total_count"] = std::stoi(row[4]);
        user["win_count"] = std::stoi(row[5]);
        mysql_free_result(res);
        return true;
    }
    public:
    user_table(
            const std::string &host,
            const std::string &user,
            const std::string &passwd,
            uint32_t port,
            const std::string &dbname
            )
    {
        _mysql = mysql_util::mysql_create(host,user,passwd,port,dbname);
        assert(_mysql != nullptr);        
    }
    ~user_table()
    {
        mysql_util::mysql_destory(_mysql);
    }
    //处理用户登录请求,并返回登录用户详细信息
    bool login(Json::Value& user)
    {
#define LOGIN_SQL "select * from user where username='%s' and password=password('%s')" 
        char sql[4096] = {0};
        sprintf(sql,LOGIN_SQL,user["username"].asCString(),user["password"].asCString());
        MYSQL_RES* res;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(!mysql_util::mysql_exec(_mysql,sql))
            {
                return false;
            }
            res = mysql_store_result(_mysql);
            if(res == nullptr)
            {
                ELOG("have no user info!!");
                return false;
            }
        }
        if(res == nullptr) return false;
        if(!select_common(user,res))
        {
            return false;
        }
        return true;
    }
    //处理用户注册请求
    bool insert(Json::Value& user)
    {
        #define INSERT_SQL "insert into user values(null,1200,'%s',password('%s'),0,0);"
        char sql[4096] = {0};
        sprintf(sql,INSERT_SQL,user["username"].asCString(),user["password"].asCString());
        if(!mysql_util::mysql_exec(_mysql,sql))
        {
            ELOG("mysql execute query error: ");
            return false;
        }
        DLOG("mysql execute success!");
        return true;
    }
    
    //通过用户名获取用户信息
    bool select_by_name(const std::string& username,Json::Value& user)
    {
        //先执行SQL
        std::string sql = "select * from user where username=";
        sql += "'"+username+"'";
        MYSQL_RES* res;
        bool ret;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            ret = mysql_util::mysql_exec(_mysql,sql.c_str());
            if(ret == false)
            {
                DLOG("get user by name failed!");
                return false;
            }
            res = mysql_store_result(_mysql);
            if(res == nullptr)
            {
                ELOG("have no user info!!");
                return false;
            }
        }
        ret = select_common(user,res);
        if(ret == false)
        {
            return false;
        }
        return true;
    }
    //通过用户ID获取用户信息
    bool select_by_id(uint64_t id,Json::Value& user)
    {
        std::string sql = "select * from user where id=";
        sql+=std::to_string(id);
        MYSQL_RES* res;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(!mysql_util::mysql_exec(_mysql,sql))
            {
                ELOG("mysql execute error");
                return false;
            }
            res = mysql_store_result(_mysql);
            if(res == nullptr)
            {
                ELOG("have no user info!!");
                return false;
            }
        }
        if(!select_common(user,res))
        {
            return false;
        }
        return true;
    }
    //胜利时天梯分数增加30分，总场次增加1，胜利场次增加1
    bool win(uint64_t id)
    {
#define USER_WIN "update user set score=score+30,total_count=total_count+1,win_count=win_count+1 where id=%llu"
        char sql[4096];
        sprintf(sql,USER_WIN,id);
        if(!mysql_util::mysql_exec(_mysql,sql))
        {
            ELOG("%llu user win information commit failed!",id);
            return false;
        }
        return true;

    }
    //失败时天梯分数减少30分，总场次增加1
    bool lose(uint64_t id)
    {
#define USER_LOSE "update user set score=score-30,total_count=total_count+1 where id=%llu"
        char sql[4096];
        sprintf(sql,USER_LOSE,id);
        if(!mysql_util::mysql_exec(_mysql,sql))
        {
            ELOG("%llu user lose information commit failed!",id);
            return false;
        }
        return true;       
    }
    private:
    MYSQL* _mysql; //操作句柄
    std::mutex _mutex; //防止多线程同时使用句柄时造成的线程安全问题
};

#endif